﻿using Admin.Infra;
using Admin.Models;
using Ionic.Zip;
using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Driver.Builders;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;

namespace Admin.Controllers
{
    public class PluginController : Controller
    {
        public readonly PluginsDBContext pluginContext = new PluginsDBContext();
        public readonly IncludesDBContext includeContext = new IncludesDBContext();

       
     

        public ActionResult Plugin()
        {
            var viewModel = new ViewModel();
            viewModel.Plugins = pluginContext.Plugins.FindAll().ToList();
            var json = new Plugin();
            json.Modes = new List<Mode>();
           // json.PageIDs = new List<int>();
            var jsonSerializer = new System.Web.Script.Serialization.JavaScriptSerializer();
            viewModel.PluginJson = jsonSerializer.Serialize(json);
            return View(viewModel);
        }

        [HttpPost]
        public JsonResult Plugin(Plugin plugin)
        {
            SetUpSolution(plugin);
            string finalFolder = string.Concat(SolutionTempLocation, plugin.PluginName);
            using (ZipFile zip = new ZipFile())
            {
                zip.AddDirectory(finalFolder);
                zip.Save(string.Concat(SolutionTempLocation, plugin.PluginName, ".zip"));
                Directory.Delete(finalFolder, true);
            }
            Upsert(plugin);
            return Json(new { url = Url.Content("~/Content/temp/" + plugin.PluginName + ".zip"), plugin = plugin }, JsonRequestBehavior.AllowGet);
        }

        private void Upsert(Plugin plugin)
        {
            if (string.IsNullOrEmpty(plugin._id))
                plugin._id = ObjectId.GenerateNewId().ToString();
            plugin.Modes = plugin.Modes.Select(p =>
            {
                p._id = ObjectId.GenerateNewId().ToString();
                return p;
            }).ToList();
            pluginContext.Plugins.Update(Query.EQ("PluginName", plugin.PluginName),
                                         Update.Replace(plugin),
                                         UpdateFlags.Upsert);
        }

        private void SetUpSolution(Plugin plugin)
        {
            DirectoryCopy(PluginTemplateLocation, string.Concat(SolutionTempLocation, plugin.PluginName), true);
            DirectoryRename(plugin);
            RenameFiles(plugin);
            SetControllerActions(plugin);
        }

        private void SetControllerActions(Plugin plugin)
        {
            IEnumerable<string> list = Directory.GetFiles(string.Concat(SolutionTempLocation, plugin.PluginName), string.Concat(plugin.PluginName, "Controller.cs"), SearchOption.AllDirectories);
            string currentFile = string.Empty;

            //replace token in files
            foreach (string file in list)
            {
                currentFile = System.IO.File.ReadAllText(file);
                if (currentFile.Contains("$modes$"))
                {
                    StringBuilder sb = new StringBuilder();
                    foreach (var mode in plugin.Modes)
                    {
                        //var pairs = mode.ModeProperties.Select(x => string.Format("{0} {1} {2} {3}", x.Key, x.PropertyName, "=", x.Value)).ToArray();
                        //string args = string.Join(",", pairs);
                        //sb.Append(string.Format(ActionMethodFormat, mode.ModeName, args));
                    }
                    currentFile = currentFile.Replace("$modes$", sb.ToString());

                    using (StreamWriter streamWriter = new StreamWriter(file))
                    {
                        streamWriter.Write(currentFile);
                    }
                }
            }

        }

      

        //Copy template to temp
        private void DirectoryCopy(string sourceDirName, string destDirName, bool copySubDirs)
        {
            DirectoryInfo dir = new DirectoryInfo(sourceDirName);
            DirectoryInfo[] dirs = dir.GetDirectories();

            // If the source directory does not exist, throw an exception.
            if (!dir.Exists)
            {
                throw new DirectoryNotFoundException(
                    "Source directory does not exist or could not be found: "
                    + sourceDirName);
            }

            // If the destination directory does not exist, create it.
            if (!Directory.Exists(destDirName))
            {
                Directory.CreateDirectory(destDirName);
            }


            // Get the file contents of the directory to copy.
            FileInfo[] files = dir.GetFiles();

            foreach (FileInfo file in files)
            {
                // Create the path to the new copy of the file.
                string temppath = Path.Combine(destDirName, file.Name);

                // Copy the file.
                file.CopyTo(temppath, false);
            }

            // If copySubDirs is true, copy the subdirectories.
            if (copySubDirs)
            {
                foreach (DirectoryInfo subdir in dirs)
                {
                    // Create the subdirectory.
                    string temppath = Path.Combine(destDirName, subdir.Name);

                    // Copy the subdirectories.
                    DirectoryCopy(subdir.FullName, temppath, copySubDirs);
                }
            }
        }

        //rename directory name with token
        private void DirectoryRename(Plugin plugin)
        {
            IEnumerable<string> list = Directory.GetDirectories(string.Concat(SolutionTempLocation, plugin.PluginName), "$pluginname$", SearchOption.AllDirectories);
            foreach (var item in list)
            {
                DirectoryInfo dir = new DirectoryInfo(item);
                dir.MoveTo(item.Replace("$pluginname$", plugin.PluginName));
            }
        }

        //rename files and replace tokens inside filess
        private void RenameFiles(Plugin plugin)
        {
            string[] filePaths = Directory.GetFiles(string.Concat(SolutionTempLocation, plugin.PluginName), "*.*", SearchOption.AllDirectories);
            string currentFile = string.Empty;

            //replace token in files
            foreach (string file in filePaths)
            {
                currentFile = System.IO.File.ReadAllText(file);
                if (currentFile.Contains("$pluginname$"))
                {
                    currentFile = currentFile.Replace("$pluginname$", plugin.PluginName);
                    using (StreamWriter streamWriter = new StreamWriter(file))
                    {
                        streamWriter.Write(currentFile);
                    }
                }
            }
            foreach (string file in filePaths)
            {
                string currentFileName = Path.GetFullPath(file);
                currentFileName = currentFileName.Replace("$pluginname$", plugin.PluginName);
                System.IO.File.Move(file, currentFileName);
            }
        }

        private const string SolutionTempLocation = @"C:\CatNav\Google Code\Asp.net MVC MVC 4 Integration\Admin\Content\temp\";
        private const string PluginTemplateLocation = @"C:\CatNav\Google Code\Asp.net MVC MVC 4 Integration\Admin\Content\PluginTemplate\";
        private const string ActionMethodFormat = @"public ActionResult {0}({1}) 
                                                    {{
                                                        return View();
                                                    }}
                                                    ";

    }
}
